

//#include "xsdk_config.h"
#include "xapp_config.h"

#if USER_CHECK_ENABLED( ALARMCLOCK )

#include <string.h> 
#include <stdbool.h>

#include "xapp_alarmclock.h"
#include "xapp_clock.h"
#include "xapp_fstore.h"
#include "memory/user_flash_map.h"
#include "xapp_osllv.h"

#if USER_CHECK_LOG_ENABLED( ALARMCLOCK )
#include "log.h"
#define LOG     LOG_INFO 
#define LOG0    LOG_INFO0 
#define LOG1    LOG_INFO1
#define LOG2    LOG_INFO2
#define LOG3    LOG_INFO3
#else 
#define LOG(...) 
#define LOG0(...)
#define LOG1(...)
#define LOG2(...)
#define LOG3(...)
#endif 

#define ALARM_CLOCK_WEEKDAY_MASK        0x7F
#define ALARM_CLOCK_REPEAK_MASK         0x80 

static xapp_task_alarmclock_t           m_task_alarmclock[ ALARMCLOCK_MAX_NB ]; 
static bool                             m_local_alarmclock_fs_write = true; 
static bool                             m_local_alarmclock_is_require_save = false; 

static xapp_alarmclock_desc_t           alarmclock_desc;
static xapp_task_alarmclock_t           m_task_temp_alarmclock;

FSTORE_DEF( fs_alarmclock ) = FSTORE_ALARMCLOCK_CONFIG();

//////////////////////////////////////////////////////////////////////////////////////////////////
void xapp_alarmclock_init(void)
{
    uint8_t * pdata = (uint8_t*)&m_task_alarmclock;
    int res = xapp_fstore_recovery_update_record( 
                                                        pdata, 
                                                        sizeof( m_task_alarmclock), 
                                                        &fs_alarmclock        
                                                    );
    if( res == 0)
    {
        m_local_alarmclock_fs_write = false;
    }
}


void xapp_alarmclock_store(void)
{
    if( m_local_alarmclock_is_require_save )
    {
        m_local_alarmclock_is_require_save = false;

        xapp_fstore_data_op_t op; 
        // op.cb = NULL;
        op.len =  sizeof( m_task_alarmclock );
        op.pdata = (uint8_t*)&m_task_alarmclock; 
        op.fs = &fs_alarmclock;

        if( m_local_alarmclock_fs_write )
        {
            m_local_alarmclock_fs_write = false; 
            xapp_fstore_store( & op );
        }
        else
        {
            xapp_fstore_update( & op ); 
        }
    }
}


void xapp_alarmclock_on_time_update( void )
{    
    const datetime_t *pdt = xapp_clock_get_now();
    uint16_t time = ((pdt->hour << 8) & 0xff00 ) | (pdt->minute & 0xff );
    uint8_t day_of_week = pdt->weekday;
    
    for(int i = 0; i < ALARMCLOCK_MAX_NB; i++)
    {
        if( m_task_alarmclock[i].enabled == 0) // if alarmclock enabled 
        {
            continue;
        }

        if( (m_task_alarmclock[i].repeat.value & (1 << day_of_week)) == 0 ) // if weekday enabled 
        {
            continue;
        }

        // get alarmclock     
        xapp_task_alarmclock_t * p_alarmclock = &m_task_alarmclock[i]; 
        // check time 
        if( time == p_alarmclock->time.value )
        {
            alarmclock_desc.type        = p_alarmclock->type;
            alarmclock_desc.vibrateType = p_alarmclock->vibrateType;
            alarmclock_desc.alertTime   = p_alarmclock->activeTime;

            // trigger level & time 
            OSLLV_SEND_TAG_EXE( OSLLV_TAG_ALARMCLOCK );

            if( (p_alarmclock->repeat.bit.repeatable ) == 0)
            {
                p_alarmclock->repeat.value &= ~(1 << day_of_week);
                if( (p_alarmclock->repeat.value & ALARM_CLOCK_WEEKDAY_MASK) == 0)
                {
                    p_alarmclock->enabled = 0; // disable this alarmclock 
                }
                m_local_alarmclock_is_require_save = true;
            }
            break; 
        }
    }    
}

const xapp_alarmclock_desc_t* xapp_alarmclock_get_desc(void)
{
    return &alarmclock_desc;
}

int xapp_alarmclock_read(uint8_t index, uint8_t *data, uint16_t * p_size)
{
    if( index >= ALARMCLOCK_MAX_NB)
    {
        return 1; 
    }

    xapp_task_alarmclock_t * p_alarmclock = &m_task_alarmclock[index];
    data[0] = p_alarmclock->enabled;
    data[1] = p_alarmclock->type;
    data[2] = p_alarmclock->time.param.hour;
    data[3] = p_alarmclock->time.param.minute;
    data[4] = p_alarmclock->repeat.value;
    data[5] = p_alarmclock->vibrateType;
    data[6] = p_alarmclock->activeTime; 

    *p_size = XAPP_ALARMCLOCK_DATA_SIZE; 

    return 0; 
}

int xapp_alarmclock_write(uint8_t index, uint8_t *data, uint16_t size)
{
    xapp_task_alarmclock_t * p_alarmclock = &m_task_alarmclock[index];
    if( size == 1 && data[0] == 0)
    {
        p_alarmclock->enabled   = 0;
        return 0; 
    }
    
    if( size != XAPP_ALARMCLOCK_DATA_SIZE )
    {
        return 1; 
    }

    uint8_t enabled     = data[0];
    uint8_t type        = data[1];
    uint8_t hour        = data[2];
    uint8_t minute      = data[3];
    uint8_t repeat      = data[4];
    uint8_t vibrateType   = data[5];
    uint8_t alerttime   = data[6];

    if( hour > 23 || minute > 59)
    {
        return 1;
    }

    p_alarmclock->enabled             = enabled;
    p_alarmclock->type                = type;
    p_alarmclock->time.param.hour     = hour;
    p_alarmclock->time.param.minute   = minute;
    p_alarmclock->repeat.value        = repeat;
    p_alarmclock->vibrateType         = vibrateType;
    p_alarmclock->activeTime          = alerttime;

    m_local_alarmclock_is_require_save = true; 

    return 0; 
}


const xapp_task_alarmclock_t* xapp_alarmclock_get_by(uint8_t idx)
{
    return &m_task_alarmclock[idx];
}


xapp_task_alarmclock_t* xapp_alarmclock_get_temp(void)
{
    return &m_task_temp_alarmclock;
}

void xapp_alarmclock_edit_at(int idx)
{
    if( idx >= 4 ) 
    {
        idx = 0;
    }
    alarmclock_desc.selected = idx;
    memcpy( &m_task_temp_alarmclock, &m_task_alarmclock[idx], sizeof(m_task_temp_alarmclock) ); 
}

void xapp_alarmclock_edit_save(void)
{
    if( alarmclock_desc.selected >= 4 )
    {
        alarmclock_desc.selected = 0;
    }
    xapp_task_alarmclock_t* p_alarmclock = &m_task_alarmclock[ alarmclock_desc.selected ];
    memcpy( p_alarmclock, &m_task_temp_alarmclock, sizeof(m_task_temp_alarmclock) ); 
    m_local_alarmclock_is_require_save = true; 
}


#endif // !USER_CHEKC_ENABLED( ALARMCLOCK )
